package code

import com.google.protobuf.GeneratedMessage
import com.google.protobuf.InvalidProtocolBufferException
import com.google.protobuf.MessageLite
import org.slf4j.LoggerFactory
import java.util.*


/**
 * 消息体管理类
 * 通过配置或者程序注入的方式 根据 moduleid和actionid以及二进制协议可以得到对应的消息体
 * @author King
 */
class PBMessageManager : IMessageManager<GeneratedMessage, MessageLite> {

    private val bodyMap = HashMap<Class<out GeneratedMessage>, MessageLite>()

    private val messageMap = HashMap<Int, MutableMap<Int, MessageLite>>()

    override fun getMessage(modelId: Int, actionId: Int, body: ByteArray): MessageLite? {
        try {
            val map = messageMap[modelId] ?: return null
            val list = map[actionId] ?: return null
            return list.newBuilderForType().mergeFrom(body).build()
        } catch (e: InvalidProtocolBufferException) {
            log.error("error", e)
        }
        return null
    }

    override fun getMessage(modelId: Int, actionId: Int): MessageLite? {
        messageMap[modelId]?.let {
            return it[actionId]
        }
        return null
    }

    override fun getBody(msgCla: Class<GeneratedMessage>, body: ByteArray): MessageLite? {
        var lite= bodyMap[msgCla]
        lite?.let {
            try {
                return it.newBuilderForType().mergeFrom(body).build()
            } catch (e: InvalidProtocolBufferException) {
                log.error("error",e)
            }
        }
        try {
            val method = msgCla.getMethod("getDefaultInstance")
            lite = method.invoke(null, null) as MessageLite
            bodyMap.put(msgCla, lite)
        } catch (e: Exception) {
            log.error("error", e)
        }
        return lite
    }

    override fun addMessageCla(modelId: Int, actionId: Int, msgCla: Class<GeneratedMessage>) {
        try {
            if (msgCla == null)
                return
            val method = msgCla.getMethod("getDefaultInstance")
            val lite = method.invoke(null, null) as MessageLite
            var map= messageMap[modelId]
            if (map == null) {
                map = HashMap()
                messageMap.put(modelId, map)
            }
            map.put(actionId, lite)
        } catch (e: Throwable) {
            log.error("", e)
        }
    }

    companion object {
        private val log = LoggerFactory.getLogger(PBMessageManager::class.java)
    }

}
